﻿using HalconDotNet;
using MvCamCtrl.NET;
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Threading;

namespace NDK.AcqDevice.HikVision
{
    public class MvCameraController
    {
        #region 定义
        public event PropertyChangedEventHandler PropertyChanged;//实现父类
        private HImage Image_H;
        private AutoResetEvent HImageEvent = new AutoResetEvent(false);//采集完成信号
        MyCamera.cbOutputExdelegate cbImage;//用于回调收图

        private MyCamera myCamera = new MyCamera();

        IntPtr Ptr;
        #endregion

        public MvCameraController (IntPtr ptr)
        {
            Ptr = ptr;
        }

        #region 方法
        public HImage HalconImage (int timeout = 30000)
        {
            if(HImageEvent.WaitOne(timeout) == true)
            {
                if(Image_H?.IsInitialized() == true)
                {
                    return Image_H.Clone();
                }
            }

            return null;
        }

        public bool Connect ()
        {
            MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(Ptr, typeof(MyCamera.MV_CC_DEVICE_INFO)); //获取选择的设备信息

            int nRet = myCamera.MV_CC_CreateDevice_NET(ref device);//创建句柄
            if(MyCamera.MV_OK != nRet)
                return false;
            nRet = myCamera.MV_CC_OpenDevice_NET(); //连接相机
            if(MyCamera.MV_OK != nRet)
            {
                myCamera.MV_CC_DestroyDevice_NET();//销毁句柄
                return false;
            }
            //////////////////////可有可无/////////////////////////
            // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
            if(device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
            {
                int nPacketSize = myCamera.MV_CC_GetOptimalPacketSize_NET();
                if(nPacketSize > 0)
                {
                    nRet = myCamera.MV_CC_SetIntValueEx_NET("GevSCPSPacketSize", nPacketSize);
                    if(nRet != MyCamera.MV_OK)
                        return false;
                }
                else
                    return false;
            }
            myCamera.MV_CC_SetEnumValue_NET("AcquisitionMode", (uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);//设置采集连续模式
            myCamera.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);//设置采集触发模式
            myCamera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);//软触发

            cbImage = new MyCamera.cbOutputExdelegate(ImageCallBack);
            myCamera.MV_CC_RegisterImageCallBackEx_NET(cbImage, (IntPtr)0);//注册回调
            //myCamera.MV_CC_RegisterImageCallBackForBGR_NET(cbImage, (IntPtr)0);
            nRet = myCamera.MV_CC_StartGrabbing_NET(); //开始采集

            return true;
        }

        public bool DisConnect ()
        {
            if(MyCamera.MV_OK != myCamera.MV_CC_CloseDevice_NET())
                return false;
            if(MyCamera.MV_OK != myCamera.MV_CC_DestroyDevice_NET())
                return false;
            return true;
        }

        public bool IsConnect ()
        {
            return myCamera.MV_CC_IsDeviceConnected_NET();
        }

        public bool Snap ()
        {
            try
            {
                HImageEvent.Reset();
                int nRet = myCamera.MV_CC_SetCommandValue_NET("TriggerSoftware");
                if(MyCamera.MV_OK != nRet)
                {
                    return false;
                }
                return true;
            }
            catch(Exception ex)
            {
                return false;
            }
        }
        #endregion

        #region 备用
        private void ImageCallBack (IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            try
            {
                HImage image = new HImage();
                if(IsMonoData(pFrameInfo.enPixelType))
                {
                    image.GenImage1("byte", pFrameInfo.nWidth, pFrameInfo.nHeight, pData);
                }
                else
                {
                    if(pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
                    {
                        image.GenImageInterleaved(pData, "rgb", pFrameInfo.nWidth, pFrameInfo.nHeight, -1, "byte",
                                                  pFrameInfo.nWidth, pFrameInfo.nHeight, 0, 0, -1, 0);
                    }
                    else
                    {
                        IntPtr PbufForSaveImage = IntPtr.Zero;
                        if(PbufForSaveImage == IntPtr.Zero)
                        {
                            PbufForSaveImage = Marshal.AllocHGlobal((int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048));
                        }
                        MyCamera.MV_PIXEL_CONVERT_PARAM St = new MyCamera.MV_PIXEL_CONVERT_PARAM
                        {
                            nWidth = pFrameInfo.nWidth,
                            nHeight = pFrameInfo.nHeight,
                            pSrcData = pData,
                            nSrcDataLen = pFrameInfo.nFrameLen,
                            enSrcPixelType = pFrameInfo.enPixelType,
                            enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed,
                            pDstBuffer = PbufForSaveImage,
                            nDstBufferSize = (uint)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048)
                        };
                        myCamera.MV_CC_ConvertPixelType_NET(ref St);
                        image.GenImageInterleaved(PbufForSaveImage, "rgb", pFrameInfo.nWidth, pFrameInfo.nHeight, -1, "byte",
                                                  pFrameInfo.nWidth, pFrameInfo.nHeight, 0, 0, -1, 0);
                        Marshal.FreeHGlobal(PbufForSaveImage);
                    }
                }
                Image_H = image;
            }
            catch(Exception ex)
            {

            }
            finally
            {
                HImageEvent.Set();
            }
        }

        private bool IsMonoData (MyCamera.MvGvspPixelType mvGvspPixelType)
        {
            switch(mvGvspPixelType)
            {
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                    return true;
                default:
                    return false;
            }
        }
        #endregion
    }
}
